# coding=utf-8
import collections
import copy
import os
import random
import re
import sys
import traceback

import akshare as ak
import openpyxl
import pandas
import pandas as pd
from loguru import logger
from openpyxl.reader.excel import load_workbook
from openpyxl.styles import Font, Color

from models.stock_model import StockNumber, DayInfo
from mylib import download_all
from mylib.mycsv import sort_csv2
from send_email import send_email_xlsx
from update_sh import get_sh_down_date


def get_3down_len(today_date, sn, N=9):
    sc = f'stocks/{sn.ts_code}.csv'
    if not os.path.exists(sc):
        return None, None, None
    while not os.path.exists(sc):
        download_all.analysis_stock(sn)
    df = pandas.read_csv(sc)
    while str(df.iloc[0]['trade_date']) < str(today_date):
        download_all.analysis_stock(sn)
        df = pandas.read_csv(sc)
        if str(df.iloc[0]['trade_date']) >= str(today_date):
            logger.info(str(df.iloc[-1]['trade_date']).replace('-', ''))
            break
        else:
            logger.error(sn.name)
            return None, None, None
    today_d = None
    temp_arr = []
    temp_arr_low = []
    dis = 0
    down_times = 0
    vol2_times = 0
    d2first_low_arr = []
    for row in df.index:
        d = DayInfo(sn, df.loc[row])
        if d.trade_date_str > today_date:
            continue
        if today_d is None:
            today_d = copy.deepcopy(d)
            if today_d.trade_date_str != today_date:
                return None, None, None

        temp_arr.append(d)
        temp_arr_low.append(d.low)
        if len(temp_arr) == N:
            d2first_low_arr.append(temp_arr[0].vol)
            if len(d2first_low_arr) > 1 and d2first_low_arr[-1] * 2 < d2first_low_arr[-2]:
                vol2_times += 1
            if min(temp_arr_low) == temp_arr_low[0]:
                break
            if down_times == dis and temp_arr[0].pct_chg < 0:
                down_times += 1
            dis += 1
            temp_arr.pop(0)
            temp_arr_low.pop(0)

    # if dis < 2 or dis > 10:
    if dis < 2:
        # 距离太远的不看
        return None, None, None

    pct = round((today_d.close - temp_arr_low[0]) / temp_arr_low[0] * 100, 2)
    if pct < 0:
        # 跌破谷底的不看
        return None, None, None

    result_arr2 = [str(dis), str(pct), str(down_times), str(vol2_times)]
    # 最低价连续下跌门限
    res = re.findall('stocks/(.*).csv', sc)
    link_code_arr = res[0].split('.')
    link_code = f'{link_code_arr[1]}{link_code_arr[0]}'
    hyperlink = f'"https://xueqiu.com/S/{link_code}"'
    date_arr_hyp = f'=HYPERLINK({hyperlink})'
    logger.info(f'{today_date}, {sn.name}, {hyperlink}')
    return today_d, result_arr2, date_arr_hyp


def get_all_stock_csv_path():
    for root, dirs, files in os.walk('stocks'):
        return [os.path.join(root, item) for item in files]


def run_down(stocks, cal_date, sh_up_down_times, N):
    today_date = cal_date[0]
    dname = os.path.basename(__file__).split('.')[0]
    log_dir = f'result_{dname}'
    if not os.path.exists(log_dir):
        os.makedirs(log_dir)
    full_path_csv = f'{log_dir}/{today_date}_aaud.csv'
    f_tk = open(full_path_csv, 'w', encoding='utf-8')

    cal_date_str = ','.join(cal_date[::-1])
    sh_title = f'SH{sh_up_down_times}'
    f_tk.write(f'{cal_date_str},谷底距离,底部涨幅,{sh_title},vol翻倍,连接,名称,代码,当前价格')
    df = pd.read_csv('cal_ops/all.csv')
    full_path_txt = f'{log_dir}/{today_date}_get_aaud.txt'
    if os.path.exists(full_path_txt):
        os.remove(full_path_txt)
    logger.add(full_path_txt, format='{message}')

    # 计算各个行业有多少支
    indus_cunt_dict = collections.defaultdict(int)
    for row in df.index:
        sn = StockNumber(df.loc[row])
        if 'ST' in sn.name:
            continue
        if '退' in sn.name:
            continue
        if not str(sn.ts_code).startswith('60') \
                and not str(sn.ts_code).startswith('30') \
                and not str(sn.ts_code).startswith('00'):
            continue
        if stocks and sn.name not in stocks:
            continue
        indus_cunt_dict[sn.industry] += 1

    indus_cunt_dict2 = dict()
    for k, v in indus_cunt_dict.items():
        indus_cunt_dict2[k] = str(v).zfill(3)
    indus_cunt_dict = indus_cunt_dict2
    for row in df.index:
        sn = StockNumber(df.loc[row])
        if 'ST' in sn.name:
            continue
        if '退' in sn.name:
            continue
        if not str(sn.ts_code).startswith('60') \
                and not str(sn.ts_code).startswith('30') \
                and not str(sn.ts_code).startswith('00'):
            continue
        if stocks and sn.name not in stocks:
            continue
        logger.info(f'{row} {sn}')
        # if sn.name not in [
        #     '豪美新材',
        # ]:
        #     continue
        try:
            """
                elf.name = sn.name
                self.ts_code = sn.ts_code
                self.industry = sn.industry
                self.trade_date = df_row_data['trade_date']
                self.open = df_row_data['open']
                self.high = df_row_data['high']
                self.low = df_row_data['low']
                self.close = float(df_row_data['close'])
                self.pre_close = df_row_data['pre_close']
                self.change = df_row_data['change']
                self.pct_chg = float(df_row_data['pct_chg'])
                self.vol = df_row_data['vol']
                self.amount = df_row_data['amount']
            """
            today_d, result_arr2, date_arr_hyp = get_3down_len(today_date, sn, N)
            if today_d is None:
                continue
            result_arr_str = ','.join(result_arr2)
            w_msg = f'\n{indus_cunt_dict[sn.industry]}-{sn.industry},{result_arr_str},{date_arr_hyp},{sn.name},{sn.ts_code},{today_d.close}'
            logger.info(f'{today_date}, {sh_up_down_times}, {sn.name}, {w_msg}')
            f_tk.write(w_msg)
            f_tk.flush()
        except Exception as e:
            print(e, traceback.format_exc())

    if os.path.exists(full_path_txt):
        os.remove(full_path_txt)

    f_tk.close()
    # True 从小到大， False 从大到小
    # 当前下跌次数最多，成交量翻倍最少，距离最大
    # save_path_csv = full_path_csv.replace('.csv', f'_{cnt_number}.csv')
    if os.path.exists(full_path_csv):
        save_path_csv = full_path_csv.replace('.csv', f'_sort.csv')
        sort_csv2(save_path_csv, full_path_csv, [cal_date[0], '谷底距离', '底部涨幅'], [False, False, False])
        result_xlsx = csv2excel(save_path_csv)
        os.remove(save_path_csv)
        color_excel_file_path = red_min_value(result_xlsx)
        os.remove(result_xlsx)
        send_email_xlsx.send_xlsx(f'{today_date}_SH{sh_up_down_times}_aalow_dis_最低价距离涨幅排名',
                                  color_excel_file_path)


def red_min_value(excel_path):
    wb = load_workbook(excel_path)
    sheet = wb['Sheet1']
    # 标记最小值的背景色为红色
    color = 'FFFFFF'
    pre_date = '行业'
    for row in sheet[2:sheet.max_row]:
        for cell in row:
            if cell.col_idx == 1:
                if str(cell.value) != pre_date:
                    color = hex(random.randint(2 ** 23 + 4000000, 2 ** 24 - 1))[2:].zfill(6)
                    pre_date = str(cell.value)
            cell.fill = openpyxl.styles.PatternFill(start_color=color, end_color=color, fill_type='solid')

    # 保存工作簿
    color_excel_file_path = excel_path.replace('.xlsx', '_color.xlsx')  # 加载Excel文件
    if os.path.exists(color_excel_file_path):
        os.remove(color_excel_file_path)
    sheet.freeze_panes = "H2"
    wb.save(color_excel_file_path)
    return color_excel_file_path


def csv2excel(full_path_csv):
    # csv转excel
    try:
        excel_path = str(full_path_csv).replace('.csv', '.xlsx')
        # 读取CSV文件
        df = pd.read_csv(full_path_csv)
        df.to_excel(excel_path, index=False)
        return excel_path
    except Exception as e:
        print(e)


def get_sh_up_down_times(date_arr, sh_dict):
    sh_up_down_times = 0
    for k, sh_item in sh_dict.items():
        if k > date_arr[0]:
            continue
        zdf = sh_item.get('涨跌幅')
        if sh_up_down_times > 0 and zdf < 0:
            break
        if sh_up_down_times < 0 and zdf > 0:
            break
        if zdf < 0:
            sh_up_down_times -= 1
            continue
        if zdf > 0:
            sh_up_down_times += 1
            continue
    return sh_up_down_times


if __name__ == '__main__':
    # 计算连续多次3日底下跌；
    start_index = 0
    cal_len = 1
    N = 10
    try:
        arguments = sys.argv[1:]
        if arguments:
            start_index = int(arguments[0])
            cal_len = int(arguments[1]) if len(arguments) >= 2 else cal_len
            N = int(arguments[2]) if len(arguments) >= 3 else N
    except Exception as e:
        start_index = 0
        cal_len = 1
        N = 10
        logger.error(e)

    # cal_date = [
    #     '20240520',
    # ]
    # start_index = 367
    sh_dict, sh_date = get_sh_down_date()
    cal_date = sh_date[start_index:start_index + cal_len]
    # sh_date = [
    #     '20250904'
    # ]
    sh_up_down_times = get_sh_up_down_times(cal_date, sh_dict)
    stocks = [
        # '菜百股份',
        # '通威股份',
        # '中天科技',
        # '均胜电子',
        # '长江电力',
        # '隆基绿能',
        # '华电科工',
        # '明阳智能',
        # '众鑫股份',
    ]
    # for N in range(5, 10):
    run_down(stocks, cal_date, sh_up_down_times, N)
